package com.wzw.basics.feature.eight;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

/**
 * 对时间处理的加强，
 * 原来使用的是 Date
 * 1.非线程安全
 * 2.时区处理麻烦
 * 3.各种格式化、和时间计算繁琐
 * 4.设计有缺陷，Date 类同时包含日期和时间；还有一个 java.sql.Date，容易混淆。
 * <p>
 * 现在使用的是 {@link java.time.LocalDate} {@link java.time.LocalTime} {@link java.time.LocalDateTime}
 * LocalDate 表示当前时间，不包含时分秒
 * LocalTime 表示当前时刻，不包好年月日
 * LocalDateTime 表示当前时间戳，包含年月日时分秒
 * <p>
 * JDBC 和 java8
 * 1.Date ---> LocalDate
 * 2.Time ---> LocalTime
 * 3.TimesStamp ---> LocalDateTime
 *
 * @author Wangzhiwen
 */
public class DateTimeApi {

    public static void main(String[] args) {
        // 时间格式化 -> 时间转字符串
        OldApi.format();
        NewApi.format();

        // 字符串格式花 -> 字符串转时间
        OldApi.parse();
        NewApi.parse();
    }

}

class OldApi {

    // 原来的时间格式化
    public static void format() {
        Date now = new Date();
        // 重写了toString方法，打印出来是CST时间 Sun Aug 29 23:16:32 CST 2021
        System.out.println(now);
        //format yyyy-MM-dd HH:mm:ss
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String date = sdf.format(now);
        System.out.printf("date format : %s%n", date);

        //format HH:mm:ss
        SimpleDateFormat sdft = new SimpleDateFormat("HH:mm:ss");
        String time = sdft.format(now);
        System.out.printf("time format : %s%n", time);

        //format yyyy-MM-dd HH:mm:ss
        SimpleDateFormat sdfdt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String datetime = sdfdt.format(now);
        System.out.printf("dateTime format : %s%n", datetime);
    }

    // 字符串转时间
    public static void parse() {
        //已弃用
        Date date = new Date("2021-01-26");
        //替换为
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        try {
            // 必须显示的出来格式化异常
            Date date1 = sdf.parse("2021-01-26");
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

    // 日期计算
    public static void dateCal() {
        //一周后的日期
        SimpleDateFormat formatDate = new SimpleDateFormat("yyyy-MM-dd");
        Calendar ca = Calendar.getInstance();
        ca.add(Calendar.DATE, 7);
        Date d = ca.getTime();
        String after = formatDate.format(d);
        System.out.println("一周后日期：" + after);

        //算两个日期间隔多少天，计算间隔多少年，多少月方法类似
        String dates1 = "2021-12-23";
        String dates2 = "2021-02-26";
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date date1;
        Date date2;
        try {
            date1 = format.parse(dates1);
            date2 = format.parse(dates2);
        } catch (ParseException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        int day = (int) ((date1.getTime() - date2.getTime()) / (1000 * 3600 * 24));
        System.out.println(dates2 + "和" + dates2 + "相差" + day + "天");
        //结果：2021-12-23和2021-12-23相差300天
    }

    // 获取指定日期
    public static void appointedDay() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        //获取当前月第一天：
        Calendar c = Calendar.getInstance();
        c.add(Calendar.MONTH, 0);
        c.set(Calendar.DAY_OF_MONTH, 1);
        String first = format.format(c.getTime());
        System.out.println("first day:" + first);

        //获取当前月最后一天
        Calendar ca = Calendar.getInstance();
        ca.set(Calendar.DAY_OF_MONTH, ca.getActualMaximum(Calendar.DAY_OF_MONTH));
        String last = format.format(ca.getTime());
        System.out.println("last day:" + last);

        //当年最后一天
        Calendar currCal = Calendar.getInstance();
        Calendar calendar = Calendar.getInstance();
        calendar.clear();
        calendar.set(Calendar.YEAR, currCal.get(Calendar.YEAR));
        calendar.roll(Calendar.DAY_OF_YEAR, -1);
        Date time = calendar.getTime();
        System.out.println("last day:" + format.format(time));
    }

    // 时区 借助 TimeZone。
    public static void timezone() {
        //北京时间：Wed Jan 27 14:05:29 CST 2021
        Date date = new Date();

        SimpleDateFormat bjSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //北京时区
        bjSdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        System.out.println("毫秒数:" + date.getTime() + ", 北京时间:" + bjSdf.format(date));

        //东京时区
        SimpleDateFormat tokyoSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        tokyoSdf.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo"));  // 设置东京时区
        System.out.println("毫秒数:" + date.getTime() + ", 东京时间:" + tokyoSdf.format(date));

        //如果直接print会自动转成当前时区的时间
        System.out.println(date);
        //Wed Jan 27 14:05:29 CST 2021
    }

}

class NewApi {

    // 现在的时间格式化
    public static void format() {
        //format yyyy-MM-dd LocalDate重写了toString方法，打印出来就是 年-月-日
        LocalDate date = LocalDate.now();
        System.out.printf("date format : %s%n", date);

        //format HH:mm:ss LocalTime重写了toString方法，打印出来就是 时:分:秒
        LocalTime time = LocalTime.now().withNano(0);
        System.out.printf("time format : %s%n", time);

        //format yyyy-MM-dd HH:mm:ss 重写了toString，打印出来就是 年-月-日T时:分:秒
        LocalDateTime dateTime = LocalDateTime.now();
        // 也可以使用 DateTimeFormatter 设置时间字符串格式
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String format = dateTime.format(dateTimeFormatter);
        System.out.printf("dateTime format : %s%n", format);
    }

    // 字符串转时间
    public static void parse() {
        // of 方法设置年月日时分秒 parse 方法转换为对应时间，不必显示的处理异常
        LocalDate date = LocalDate.of(2021, 8, 29);
        LocalDate parse = LocalDate.parse(date.toString());
        System.out.println(parse);

        LocalDateTime dateTime = LocalDateTime.of(2021, 1, 26, 12, 12, 22);
        LocalDateTime.parse("2021-08-30 12:12:22");

        LocalTime time = LocalTime.of(12, 12, 22);
        LocalTime.parse("12:12:22");
    }

    // 日期计算
    public static void dateCal() {
        //一周后的日期
        LocalDate localDate = LocalDate.now();
        //方法1
        LocalDate after = localDate.plus(1, ChronoUnit.WEEKS);
        //方法2
        LocalDate after2 = localDate.plusWeeks(1);
        System.out.println("一周后日期：" + after);

        //算两个日期间隔多少天，计算间隔多少年，多少月
        LocalDate date1 = LocalDate.parse("2021-02-26");
        LocalDate date2 = LocalDate.parse("2021-12-23");
        Period period = Period.between(date1, date2);
        System.out.println("date1 到 date2 相隔："
                + period.getYears() + "年"
                + period.getMonths() + "月"
                + period.getDays() + "天");
        //打印结果是 “date1 到 date2 相隔：0年9月27天”
        //这里period.getDays()得到的天是抛去年月以外的天数，并不是总天数
        //如果要获取纯粹的总天数应该用下面的方法
        long day = date2.toEpochDay() - date1.toEpochDay();
        System.out.println(date2 + "和" + date2 + "相差" + day + "天");
        //打印结果：2021-12-23和2021-12-23相差300天
    }

    // 获取指定日期
    public static void appointedDay() {
        LocalDate today = LocalDate.now();
        //获取当前月第一天：
        LocalDate firstDayOfThisMonth = today.with(TemporalAdjusters.firstDayOfMonth());
        // 取本月最后一天
        LocalDate lastDayOfThisMonth = today.with(TemporalAdjusters.lastDayOfMonth());
        //取下一天：
        LocalDate nextDay = lastDayOfThisMonth.plusDays(1);
        //当年最后一天
        LocalDate lastday = today.with(TemporalAdjusters.lastDayOfYear());
        //2021年最后一个周日，如果用Calendar是不得烦死。
        LocalDate lastMondayOf2021 = LocalDate.parse("2021-12-31").with(TemporalAdjusters.lastInMonth(DayOfWeek.SUNDAY));
    }

    // 时区 在新特性中引入了 java.time.ZonedDateTime 来表示带时区的时间。它可以看成是 LocalDateTime + ZoneId。
    public static void timezone() {
        //当前时区时间
        ZonedDateTime zonedDateTime = ZonedDateTime.now();
        System.out.println("当前时区时间: " + zonedDateTime);

        //东京时间
        ZoneId zoneId = ZoneId.of(ZoneId.SHORT_IDS.get("JST"));
        ZonedDateTime tokyoTime = zonedDateTime.withZoneSameInstant(zoneId);
        System.out.println("东京时间: " + tokyoTime);

        // ZonedDateTime 转 LocalDateTime
        LocalDateTime localDateTime = tokyoTime.toLocalDateTime();
        System.out.println("东京时间转当地时间: " + localDateTime);

        //LocalDateTime 转 ZonedDateTime
        ZonedDateTime localZoned = localDateTime.atZone(ZoneId.systemDefault());
        System.out.println("本地时区时间: " + localZoned);
    }
}
